/*
The MIT License (MIT)

Copyright (c) 2013 Mike Dapiran, Brian May, Richard Pospesel, and Bert Wierenga

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software 
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#pragma once

//#include "..\DataStructures\IList.h"
//#include "..\DataStructures\Array1D.h"
class TiXmlNode;

namespace Hogshead
{
	namespace Common
	{
		template <typename T> class IList;
		template <typename T> class Array1D;

		/**
		* String provides a basic (yet better than std::string) String class.  Care has been taken
		* to keep speed in mind, so some features (such as concatanation of strings via + and +=) have not
		* been implemented.  For these types of operations, use StringBuilder.  
		*
		* String can be used anywhere where const char* is used since the (const char*) casting operator is implemented.
		*
		* The primitive type constructors (apart from char, unsigned char, and bool) use the sprintf to convert
		* to text.
		* @see StringBuilder
		*/
		class String
		{

		public:
			String();
			~String();

			/**
			* A simple copy constructor.  Performs a deep copy on the other String's char array and copies the length.
			* @param in_other The other String we want to copy.
			*/
			String(const String& in_other);
			/**
			* A char* constructor.  Copies a nul terminated char array into local storage.
			* @param in_char_array The char array we want to copy.
			*/
			String(const char* in_char_array);
			/**
			* Another char* constructor.  Copies a number of bytes, starting from an offset, to this String.
			* @param in_char_array The source array we are copying from.
			* @param in_offset The number of bytes from the beginning of in_char_array to start from
			* @param in_length The number of bytes to copy in
			*/
			explicit String(const char* in_char_array, int in_offset, int in_length);

			/**
			* Simple constructor which creates a String from a single char.
			* @param in_char The single character we want to set our String to.
			*/
			explicit String(char in_char);
			/**
			* Simple constructor which creates a String from a single unsigned char.
			* @param in_char The single unsigned character we want to set our String to.
			*/
			explicit String(unsigned char in_uchar);
			/**
			* Constructor which creates a String from a bool.  When true, the resulting
			* String will be "True" and when false, the String will be "False"
			* @param in_bool The single bool we want to set our String to.
			*/
			explicit String(bool in_bool);
			/**
			* Constructor which creates a String from a 32-bit int.
			* @param in_int The int we want to set our String to.
			*/
			explicit String(int in_int);
			/**
			* Constructor which creates a String from an unsigned 32-bit int.
			* @param in_uint The int to set our String to.
			*/
			explicit String(unsigned int in_uint);
			/**
			* Constructor which creates a String from a 64-bit int.
			* @param in_long_long The long long to set our String to.
			*/
			explicit String(long long in_long_long);
			/**
			* Constructor which creates a String from an unsigned 64-bit int.
			* @param in_ulong_long the unsigned long long to set our String to.
			*/
			explicit String(unsigned long long in_ulong_long);
			/**
			* Constructor which creates a String from a given float. Not-a-number
			* evaluates to "NaN", positive infinity evaluates to "Infinity" and 
			* negative infinity evaluates to "-Infinity".  Six decimal places
			* are calculated.
			* @param in_float the float to set our String to.
			*/
			explicit String(float in_float);
			/**
			* Constructor which creates a String from a given float. Not-a-number
			* evaluates to "NaN", positive infinity evaluates to "Infinity" and 
			* negative infinity evaluates to "-Infinity".  Fifteen decimal
			* places are calculated.
			* @param in_float the float to set our String to.
			*/
			explicit String(double in_double);

			/**
			* Constructs a String from a passed in List<char>.
			* @param in_chars A List of characters to convert to a String.
			*/
			explicit String(IList<char>& in_chars);

			/**
			* Constructs a String from a passed in pointer.  The value will be
			* the address.
			* @param in_pointer A pointer
			*/

			explicit String(const void* in_pointer);
			/**
			* Constructs a String from a passed in TiXMLNode
			* @param in_node A TiXmlNode object
			*/
//			explicit String(const TiXmlNode& in_node);

			/**
			* Returns the number of ASCII characters in this String.
			*/
			int length() const;

			/*
			* Casts the String object to a const char*.  This allows String to be used transparently where nul
			* terminated const char* are expected.  Also, since the return is const, we don't need to worry 
			* about other people deleting our _string_data.
			*/
			operator const char*() const;

			/*
			* Determine if this is equal to passed in string
			* @param in_string The string to compare to this.
			*/
			bool equals(const String& in_string) const;

			/**
			* Equivalence operators
			*/
			bool operator==(const String& in_string) const;
			bool operator==(const char* in_string) const;
			friend bool operator==(const char* left, const String& right);

			/**
			* Inequivalence operators
			*/

			bool operator!=(const String& in_string) const;
			bool operator!=(const char* in_string) const;
			friend bool operator!=(const char* left, const String& right);

			String& operator=(const String& right);
			String& operator=(const char* right);

			static bool equals(const char* left, const char* right);
			char operator[](int in_index) const;

			Array1D<String> split(char c) const;
			Array1D<String> split(const String& s) const;
		private:
			char* _string_data;
			int _length;
		};
	}
}